﻿using Blm.PgsqlDriver.Helpers;
using Blm.Utils.Extensions;
using ClosedXML.Report.Utils;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Npgsql;
using NpgsqlTypes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using VisionCloud.Core;
using VisionCloud.Core.Model.Enums;
using VisionCloud.Core.Model.Ms;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.DtoModel.MiniApp;
using VisionCloud.Domain.DtoModel.Ms;
using VisionCloud.Domain.Repository.Interface.Ms;
using VisionCloud.Domain.UnitOfWork;
using VisionCloud.Utility;
using static VisionCloud.Core.Model.Ms.TaskPoints;

namespace VisionSurface.Service.Ms
{
    public class TaskManageService
    {
        public BlueDbContext Db { get; set; }

        public IUnitOfWork UnitOfWork { get; set; }

        public IMsTaskRepository MsTaskRepository { get; set; }

        public IMsProjectRepository MsProjectRepository { get; set; }

        public IMsHouseMapRepository MsHouseMapRepository { get; set; }

        public IMsTaskPointsRepository MsTaskPointsRepository { get; set; }

        public IMsTaskReportRepository MsTaskReportRepository { get; set; }

        public IMsPointTypeRepository MsPointTypeRepository { get; set; }

        public IMsMeasureItemRepository MsMeasureItemRepository { get; set; }

        public IMsTaskStandardRepository MsTaskStandardRepository { get; set; }

        public IMsTaskWxMessageRepository MsTaskWxMessageRepository { get; set; }

        public IMsProjectStandardRepository MsProjectStandardRepository { get; set; }

        public IMsMeasureTemplateRepository MsMeasureTemplateRepository { get; set; }

        public IMsTaskMeasureItemTemplateRepository MsTaskMeasureItemTemplateRepository { get; set; }

        public IMSTaskPoint2ManualMeasurementRepository MSTaskPoint2ManualMeasurementRepository { get; set; }

        public IMsDotCloudCollectRepository MsDotCloudCollectRepository { get; set; }

        public IDotCloudUploadRepository MsDotCloudUploadRepository { get; set; }

        public IMsTaskDotCloudBatchRepository MsTaskDotCloudBatchRepository { get; set; }

        public AlgoTemplateService AlgoTemplateService { get; set; }

        private OperatorInfo tokenModel => OperatorProvider.Get();

        /// <summary>
        /// 工程阶段枚举和ProjectStandardId映射记录
        /// </summary>
        public static readonly List<ProjectStandardMapDto> ProjectStandardMaps = new List<ProjectStandardMapDto>
        {
            new ProjectStandardMapDto{  ProjectStage = ProjectStageEnum.结构工程, ProjectStandardId = Guid.Parse("0dfe9175-0e7b-4288-9eec-0589a3fbd585") },
            new ProjectStandardMapDto{  ProjectStage = ProjectStageEnum.砌筑工程, ProjectStandardId = Guid.Parse("604ea8aa-a666-4275-80f7-cd1e6ec0e9de") },
            new ProjectStandardMapDto{  ProjectStage = ProjectStageEnum.抹灰工程, ProjectStandardId = Guid.Parse("e47f7e43-47a7-4eb1-8a41-f6d48e775e72") },
            new ProjectStandardMapDto{  ProjectStage = ProjectStageEnum.装饰工程, ProjectStandardId = Guid.Parse("a92e1059-c1dd-4a1f-8470-514095381c46") }
        };
        private readonly IConfiguration cfg;

        public TaskManageService(IConfiguration cfg)
        {
            this.cfg = cfg;
        }

        /// <summary>
        /// 查询小程序创建的任务列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async ValueTask<List<TaskInfoResponseDto>> GetTaskListAsync(QueryTaskRequestDto dto)
        {
            Guid? projectStandardId = dto.ProjectStage == null ? (Guid?)null : ProjectStandardMaps.FirstOrDefault(p => p.ProjectStage == dto.ProjectStage).ProjectStandardId;
            var list = await MsTaskRepository.GetTaskListAsync(dto, tokenModel.Id, projectStandardId);
            var needUploadList = await MsDotCloudCollectRepository.QueryNeedUploadPointListAsync(list?.Select(p => p.TaskId).ToArray());
            list.ForEach(p =>
            {
                var needUploadPoints = needUploadList.Where(x => x.TaskId == p.TaskId).Select(x => x.FilePath);
                p.IsNeedUpload = needUploadPoints.Any(x => !string.IsNullOrEmpty(x));
            });
            return list;
        }

        /// <summary>
        /// 查询当前用户是否拥有某个项目的权限
        /// </summary>
        /// <param name="projectId"></param>
        /// <returns></returns>
        public async ValueTask<bool> CheckProjectAuth(Guid projectId)
        {
            string sql;
            if (tokenModel.IsCompanyAdmin)
            {
                sql = $@"SELECT EXISTS(SELECT 1 FROM ""MsProject""
	                    where ""CompanyGuid"" = '{tokenModel.CompanyGuid}' and ""IsDeleted"" = false);";
            }
            else
            {
                sql = $@"SELECT EXISTS(SELECT 1 FROM ""vw_user_project_info""
                         where ""YunUserGuid"" = '{tokenModel.Id}' and ""ProjectId"" = '{projectId}' and ""IsDeleted"" = false)";
            }


            return await PgSqlHelper.QueryScalarAsync<bool>(sql);
        }

        /// <summary>
        /// 新增任务
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async ValueTask<MsTask> AddTask(TaskFm model)
        {
            model.Craft = model.Craft ?? "";
            var isExists = await CheckProjectAuth(model.ProjectId);
            if (!isExists)
                throw new OperationException("NoAuthorized".SurfaceLocalizer());

            model.UserId = tokenModel.Id;
            model.HouseMapPoints = await MsHouseMapRepository.GetPointTypes(model.ProjectId, model.HouseMapId);
            if (model.HouseMapPoints.IsEmpty())
                throw new OperationException("B00557".SurfaceLocalizer());

            return model.MeasureType switch
            {
                MeasureTypeEnum.实测实量任务 => await AddorUpdateTask(model),
                MeasureTypeEnum.机器人任务 => await AddOrUpdateRobotTask(model),
                MeasureTypeEnum.建模任务 or MeasureTypeEnum.排版任务 => await AddorUpdateModelingTask(model),
                _ => throw new OperationException("NotSupportedTask".SurfaceLocalizer())
            };
        }

        /// <summary>
        /// 新增或更新实测实量任务
        /// </summary>
        /// <param name="model">任务Dto</param>
        /// <param name="update">是否更新</param>
        /// <returns></returns>
        private async Task<MsTask> AddorUpdateTask(TaskFm model, bool update = false)
        {
            var executionTypeArr = new string[] { "1", "2" };
            if (model.TaskExecutionType != null && !executionTypeArr.Contains(model.TaskExecutionType))
                throw new OperationException("YB0060".SLocalize());

            //项目信息
            var project = await MsProjectRepository.GetByIdAsync(model.ProjectId);

            #region 检查楼栋楼层是否存在

            var details = project.Details.ToObject<List<Detail>>();
            var building = details.FirstOrDefault(w => w.Building == model.BuildingBlock);
            if (details == null)
                throw new OperationException("B00504".SurfaceLocalizer());
            var isFloorInt = int.TryParse(model.BuildingFloor, out int floorInt);
            if (!isFloorInt || floorInt <= 0 || building.Floor.ToInt32() < floorInt)
                throw new OperationException("B00504".SurfaceLocalizer());

            #endregion

            // 取测量标准库
            MsProjectStandard stand = await MsProjectStandardRepository.GetProjectStandard(model.ProjectStandardId, model.ProjectId);
            if (stand == null)
                throw new OperationException("B00551".SurfaceLocalizer(model.ProjectStandardId));
            if (string.IsNullOrEmpty(stand.Content))
                throw new OperationException("B00552".SurfaceLocalizer(stand.Stage));

            var textReader = new JsonTextReader(new StringReader(stand.Content));
            JArray jsonArray = (JArray)new JsonSerializer().Deserialize(textReader);
            textReader.Close();
            foreach (var item in jsonArray)
            {
                // 拷贝标准库
                model.UsestandardAllInfo = item.ToString();
            }
            var staObj = JArray.Parse(stand.Content);
            Guid taskId = update ? model.TaskId : Guid.NewGuid();
            var entity = model.CopyTo<TaskFm, MsTask>(t =>
            {
                t.TaskId = taskId;
                t.Status = MsTask.TaskStatus.未完成;
                t.UseStandards = model.UseStandards.ToJsonStr();
                t.HouseHolds = model.HouseHolds;
                t.IsNew = true;
                t.LastUpdatedDate = DateTime.Now;
                t.SupportStandard = building.Standard;
                t.UsestandardAllInfo = model.UsestandardAllInfo;
                t.HouseMapPoints = string.Empty;
                t.AlgorithmParamTemplateGuid = model.AlgorithmParamTemplateGuid;
                t.AlgorithmParamTemplateName = model.AlgorithmParamTemplateName;
                t.TaskExecutionType = model.TaskExecutionType;
                t.SecondaryStructureType = model.SecondaryStructureType;
                t.MeasureType = model.MeasureType.ToInt32().ToString();
            });
            await FilterTask(entity);

            var houseMapModel = await MsHouseMapRepository.GetByIdAsync(model.HouseMapId);
            entity.HouseType = houseMapModel?.HouseType;
            if (update)
            {
                //修改操作 名称和名称编号不变
                var oldTask = await MsTaskRepository.GetMsTask(model.TaskId);
                // 更新使用原来TaskId
                entity.TaskId = model.TaskId;
                entity.TaskName = oldTask.TaskName;
                entity.TaskNameNo = oldTask.TaskNameNo;
                if (!string.IsNullOrWhiteSpace(model.TaskProperty))
                {
                    entity.TaskName = entity.TaskName.Substring(0, entity.TaskName.LastIndexOf(oldTask.TaskProperty)) + model.TaskProperty;
                }
                // 任务创建者和UserId一致
                entity.UserId = oldTask.CreatedBy;
                MsTaskRepository.Update(entity);
            }
            else
            {
                entity.TaskName = $"{project.Name}-{model.BuildingBlock}栋-{model.BuildingFloor}层";
                // 任务创建者和UserId一致
                entity.UserId = tokenModel.Id;
                if (!string.IsNullOrEmpty(model.HouseHolds) && model.HouseHolds != "-1")
                {
                    entity.TaskName += $"-{model.BuildingFloor + model.HouseHolds.PadLeft(2, '0')}";
                }
                if (!string.IsNullOrWhiteSpace(model.TaskProperty))
                {
                    entity.TaskName += $"-{model.TaskProperty}";
                }
                MsTaskRepository.Add(entity);
            }

            #region 测量项模板拷贝到任务测量项模板

            var taskTemplates = new List<MsTaskMeasureItemTemplate>();
            // 任务是否存在
            var existedTask = await MsTaskRepository.GetMsTask(entity.TaskId);
            if (existedTask == null || !string.Equals(model.HouseMapId.ToString(), existedTask.HouseMapId.ToString()))
            {
                // 删除根据任务删除站点测量项模板
                var taskMeasureItemTemplate = await MsTaskMeasureItemTemplateRepository.GetTaskMeasureItemTemplates(entity.TaskId);
                if (taskMeasureItemTemplate != null && taskMeasureItemTemplate.Count > 0)
                {
                    MsTaskMeasureItemTemplateRepository.RemoveRange(taskMeasureItemTemplate);
                }

                var templates = await MsMeasureTemplateRepository.GetMeasureTemplate(model.HouseMapId);
                if (templates.IsNotEmpty())
                {
                    var allStandards = model.UsestandardAllInfo.ToObject<StandardClass>();
                    if (allStandards?.Items == null || allStandards.Items.Count == 0)
                    {
                        throw new OperationException("B00555".SurfaceLocalizer());
                    }
                    foreach (var item in templates)
                    {
                        var taskTemplate = item.CopyTo<MsTaskMeasureItemTemplate>();
                        taskTemplate.MsTaskMeasureItemTemplateId = Guid.NewGuid();
                        taskTemplate.DesignValues = item.DesignValues.ToJsonStr();
                        taskTemplate.TaskId = entity.TaskId;
                        taskTemplate.StandardValues = string.Empty;
                        taskTemplate.Unit = "mm";
                        taskTemplate.Type = item.Type;
                        // 设置标准值
                        if (allStandards.Items.Exists(x => x.Code == item.Code))
                        {
                            var st = allStandards.Items.Where(x => x.Code == item.Code).FirstOrDefault();
                            taskTemplate.StandardValues = $"{{\"Value\":{st.Value ?? "[]"},\"Walue\":{st.WValue ?? "[]"},\"DValue\":{st.DValue ?? "[]"}}}";
                            taskTemplate.WarningValue = allStandards.WarningValue;
                        }
                        taskTemplates.Add(taskTemplate);
                    }
                    MsTaskMeasureItemTemplateRepository.AddRange(taskTemplates);
                }
            }
            else
            {
                taskTemplates = await MsTaskMeasureItemTemplateRepository.GetTaskMeasureItemTemplates(entity.TaskId);
            }

            #endregion 测量项模板拷贝到任务测量项模板

            // 删除任务站点
            var points = await MsTaskPointsRepository.GetTaskPoints(entity.TaskId);
            if (points != null && points.Count > 0)
            {
                MsTaskPointsRepository.RemoveRange(points);
            }

            // 删除站点测量项
            var measurementItem = await MSTaskPoint2ManualMeasurementRepository.GetMeasurement2PointDto(entity.TaskId);
            if (measurementItem.IsNotEmpty())
            {
                MSTaskPoint2ManualMeasurementRepository.RemoveRange(measurementItem);
            }

            #region 任务测量项新增/更新

            var pointTypes = await MsPointTypeRepository.GetListByProjectId(model.ProjectId, false);
            if (model.PointTypes.IsEmpty())
            {
                throw new OperationException("B00558".SurfaceLocalizer());
            }

            // 根据阶段取标准测量项
            var taskStandardMeasureItems = await MsTaskStandardRepository.GetTaskStandards(model.TaskId);
            if (taskStandardMeasureItems.IsNotEmpty())
            {
                MsTaskStandardRepository.RemoveRange(taskStandardMeasureItems);
            }
            // 计算人工测量项数
            int robotMeasureItemCnt = 0;
            List<MsTaskStandard> taskStandards = new List<MsTaskStandard>();
            foreach (var st in model.PointTypes)
            {
                foreach (var mi in st.MeasureItem)
                {
                    var standard = mi.CopyTo<MsTaskStandard>();
                    standard.Id = Guid.NewGuid();
                    standard.TaskId = entity.TaskId;
                    standard.MsPointTypeId = st.Id;
                    if (standard.IsChecked)
                    {
                        robotMeasureItemCnt++;
                    }
                    taskStandards.Add(standard);
                }
                if (robotMeasureItemCnt == 0)   // 站点类型机器测量项必须
                {
                    throw new OperationException("B00559".SurfaceLocalizer(st.Name));
                }
                robotMeasureItemCnt = 0;
            }
            // 更新任务标准库
            MsTaskStandardRepository.AddRange(taskStandards);

            #endregion 任务测量项新增/更新

            List<TaskPoints> taskPoints = new List<TaskPoints>();
            List<MSTaskPoint2ManualMeasurement> measureItems = new List<MSTaskPoint2ManualMeasurement>();
            if (model.IsCopyTask)
                (taskPoints, measureItems) = await CopyTaskPoints(model, entity, true, taskTemplates);
            else
                (taskPoints, measureItems) = await GetTaskPoints(model, entity, pointTypes, true, taskTemplates);

            MsTaskPointsRepository.AddRange(taskPoints);
            MSTaskPoint2ManualMeasurementRepository.AddRange(measureItems);

            //添加任务算法模板
            await AlgoTemplateService.AddTaskAlgoTempItem(taskId, model.AlgorithmParamTemplateGuid, model.ProjectId);

            await UnitOfWork.SaveChangesAsync();

            return entity;
        }

        /// <summary>
        /// 新增或更新机器人任务
        /// </summary>
        /// <param name="model"></param>
        /// <param name="update"></param>
        /// <returns></returns>
        /// <exception cref="ApiResultException"></exception>
        private async Task<MsTask> AddOrUpdateRobotTask(TaskFm model, bool update = false)
        {
            if (model.ProjectStandardId == Guid.Empty)
                throw new OperationException("B00549".SurfaceLocalizer());
            if (model.RobotCategory == null || model.RobotCategory.Count < 1)
                throw new OperationException("B00728".SurfaceLocalizer());
            //项目信息
            var project = await MsProjectRepository.GetByIdAsync(model.ProjectId);
            var details = project.Details.ToObject<List<Detail>>();
            var detail = details.SingleOrDefault(w => w.Building == model.BuildingBlock);
            if (detail == null)
                throw new OperationException("B00504".SurfaceLocalizer());

            // 取测量标准库
            MsProjectStandard stand = await MsProjectStandardRepository.GetProjectStandard(model.ProjectStandardId, model.ProjectId);
            if (stand == null)
                throw new OperationException("B00551".SurfaceLocalizer(model.ProjectStandardId));
            if (string.IsNullOrEmpty(stand.Content))
                throw new OperationException("B00552".SurfaceLocalizer(stand.Stage));

            // 拷贝标准库
            var textReader = new JsonTextReader(new StringReader(stand.Content));
            JArray jsonArray = (JArray)new JsonSerializer().Deserialize(textReader);
            textReader.Close();
            foreach (var item in jsonArray)
            {
                model.UsestandardAllInfo = item.ToString();
            }

            Guid taskId = update ? model.TaskId : Guid.NewGuid();
            var entity = model.CopyTo<TaskFm, MsTask>(t =>
            {
                t.TaskId = taskId;
                t.Status = MsTask.TaskStatus.未完成;
                t.UseStandards = model.UseStandards.ToJsonStr();
                t.HouseHolds = model.HouseHolds;
                t.IsNew = true;
                t.LastUpdatedDate = DateTime.Now;
                t.SupportStandard = detail.Standard;
                t.UsestandardAllInfo = model.UsestandardAllInfo;
                t.HouseMapPoints = string.Empty;
                t.TaskExecutionType = model.TaskExecutionType;
                t.RobotCategory = string.Join('|', model.RobotCategory);
                t.InnerWallRobotVersion = model.InnerWallVersion;
                t.MeasureType = model.MeasureType.ToInt32().ToString();
            });
            await FilterTask(entity);

            var houseMapModel = await MsHouseMapRepository.GetByIdAsync(model.HouseMapId);
            entity.HouseType = houseMapModel?.HouseType;
            entity.TaskName = $"{project.Name}-{model.BuildingBlock}栋-{model.BuildingFloor}层-机器人";
            if (update)
            {
                var oldTask = await MsTaskRepository.GetMsTask(model.TaskId);
                entity.TaskId = model.TaskId;
                entity.TaskNameNo = oldTask.TaskNameNo;
                // 任务创建者和UserId一致
                entity.UserId = oldTask.CreatedBy;
                MsTaskRepository.Update(entity);
            }
            else
            {
                // 任务创建者和UserId一致
                entity.UserId = OperatorProvider.Get().Id;
                MsTaskRepository.Add(entity);
            }
            // 删除任务站点
            var points = await MsTaskPointsRepository.GetTaskPoints(entity.TaskId);
            if (points.IsNotEmpty())
            {
                MsTaskPointsRepository.RemoveRange(points);
            }

            var pointTypes = await MsPointTypeRepository.GetListByProjectId(model.ProjectId, false);
            var taskPoints = new List<TaskPoints>();
            foreach (var item in model.HouseMapPoints)
            {
                #region 创建测量站点

                var taskPoint = new TaskPoints
                {
                    TaskId = entity.TaskId,
                    pointId = Guid.NewGuid(),
                    status = PointStatus.开始测量,
                    rate = RateStatus.低,
                    x = item.x,
                    y = item.y,
                    offsetX = item.offsetX,
                    offsetY = item.offsetY,
                    pintIndex = item.pointIndex,
                    HouseTypeName = item.HouseTypeName,   // 户型图名称
                    HouseTypeKey = item.HouseTypeKey,     // 户型图Key
                    UseStandards = JsonConvert.SerializeObject(new UseStandard
                    {
                        man = new List<string>(),
                        robot = new List<string> { "r-chuizhidu", "r-pingzhengdu" }
                    }),
                    MsPointTypeId = pointTypes.Where(x => x.Id == item.TypeId).FirstOrDefault().Id
                };

                #endregion 创建测量站点

                taskPoints.Add(taskPoint);
            }
            MsTaskPointsRepository.AddRange(taskPoints);
            await UnitOfWork.SaveChangesAsync();

            return entity;
        }

        /// <summary>
        /// 新增或更新建模任务
        /// </summary>
        /// <param name="model"></param>
        /// <param name="update"></param>
        /// <returns></returns>
        /// <exception cref="ApiResultException"></exception>
        private async Task<MsTask> AddorUpdateModelingTask(TaskFm model, bool update = false)
        {
            if (model.ProjectStandardId == Guid.Empty)
                throw new OperationException("B00549".SurfaceLocalizer());

            if (model.HouseMapId == Guid.Empty)
                throw new OperationException("B00554".SurfaceLocalizer());

            //项目信息
            var project = await MsProjectRepository.GetByIdAsync(model.ProjectId);
            var details = project.Details.ToObject<List<Detail>>();
            var detail = details.SingleOrDefault(w => w.Building == model.BuildingBlock);
            if (detail == null)
                throw new OperationException("B00504".SurfaceLocalizer());

            // 取测量标准库
            MsProjectStandard stand = await MsProjectStandardRepository.GetProjectStandard(model.ProjectStandardId, model.ProjectId);
            if (stand == null)
                throw new OperationException("B00551".SurfaceLocalizer(model.ProjectStandardId));

            if (string.IsNullOrEmpty(stand.Content))
                throw new OperationException("B00552".SurfaceLocalizer(stand.Stage));

            // 拷贝标准库
            var textReader = new JsonTextReader(new StringReader(stand.Content));
            JArray jsonArray = (JArray)new JsonSerializer().Deserialize(textReader);
            textReader.Close();
            foreach (var item in jsonArray)
            {
                model.UsestandardAllInfo = item.ToString();
            }
            var staObj = JArray.Parse(stand.Content);
            Guid taskId = update ? model.TaskId : Guid.NewGuid();
            var entity = model.CopyTo<TaskFm, MsTask>(t =>
            {
                t.TaskId = taskId;
                t.Status = MsTask.TaskStatus.未完成;
                t.UseStandards = model.UseStandards.ToJsonStr();
                t.HouseHolds = model.HouseHolds;
                t.IsNew = true;
                t.LastUpdatedDate = DateTime.Now;
                t.SupportStandard = detail.Standard;
                t.UsestandardAllInfo = model.UsestandardAllInfo;
                t.HouseMapPoints = string.Empty;
                t.TaskExecutionType = "1";
                t.SecondaryStructureType = model.SecondaryStructureType;
                t.TaskType = TaskTypeEnum.巡检;
                t.TaskProperty = "建模";
                t.MeasureType = model.MeasureType.ToInt32().ToString();
            });
            await FilterTask(entity);

            var houseMapModel = await MsHouseMapRepository.GetByIdAsync(model.HouseMapId);
            entity.HouseType = houseMapModel?.HouseType;
            if (update)
            {
                //修改操作 名称和名称编号不变
                var oldTask = await MsTaskRepository.GetMsTask(model.TaskId);
                // 更新使用原来TaskId
                entity.TaskId = model.TaskId;
                entity.TaskName = oldTask.TaskName;
                entity.TaskNameNo = oldTask.TaskNameNo;
                if (!string.IsNullOrWhiteSpace(model.TaskProperty))
                {
                    entity.TaskName = entity.TaskName.Substring(0, entity.TaskName.LastIndexOf(oldTask.TaskProperty)) + model.TaskProperty;
                }
                // 任务创建者和UserId一致
                entity.UserId = oldTask.CreatedBy;
                MsTaskRepository.Update(entity);
            }
            else
            {
                entity.TaskName = $"{project.Name}-{model.BuildingBlock}栋-{model.BuildingFloor}层-{entity.TaskProperty}";
                // 任务创建者和UserId一致
                entity.UserId = OperatorProvider.Get().Id;
                if (!string.IsNullOrEmpty(model.HouseHolds) && model.HouseHolds != "-1")
                {
                    entity.TaskName += $"-{model.BuildingFloor + model.HouseHolds.PadLeft(2, '0')}";
                }
                MsTaskRepository.Add(entity);
            }

            // 删除任务站点
            var points = await MsTaskPointsRepository.GetTaskPoints(entity.TaskId);
            if (points.IsNotEmpty())
            {
                MsTaskPointsRepository.RemoveRange(points);
            }

            #region 任务标准测量项新增/更新

            //获取项目的所有站点类型
            var pointTypes = await MsPointTypeRepository.GetListByProjectId(model.ProjectId, false);
            if (model.PointTypes.IsEmpty())
            {
                throw new OperationException("B00558".SurfaceLocalizer());
            }

            //删除任务标准测量项
            var taskStandardMeasureItems = await MsTaskStandardRepository.GetTaskStandards(model.TaskId);
            if (taskStandardMeasureItems.IsNotEmpty())
            {
                MsTaskStandardRepository.RemoveRange(taskStandardMeasureItems);
            }

            List<MsTaskStandard> taskStandards = new List<MsTaskStandard>();
            foreach (var st in model.PointTypes)
            {
                foreach (var mi in st.MeasureItem)
                {
                    var standard = mi.CopyTo<MsTaskStandard>();
                    standard.Id = Guid.NewGuid();
                    standard.TaskId = entity.TaskId;
                    standard.MsPointTypeId = st.Id;
                    taskStandards.Add(standard);
                }
            }

            //新增任务标准测量项
            MsTaskStandardRepository.AddRange(taskStandards);

            #endregion 任务标准测量项新增/更新

            List<TaskPoints> taskPoints = new List<TaskPoints>();
            if (model.IsCopyTask)
                (taskPoints, _) = await CopyTaskPoints(model, entity, false);
            else
                (taskPoints, _) = await GetTaskPoints(model, entity, pointTypes, false);

            MsTaskPointsRepository.AddRange(taskPoints);

            await UnitOfWork.SaveChangesAsync();

            return entity;
        }

        /// <summary>
        /// 检查该任务的项目属性是否有重复
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        private async Task FilterTask(MsTask entity)
        {
            var list = await MsTaskRepository.WhereAsNoTrackingAsync(p => p.ProjectId == entity.ProjectId
                            && p.MeasureType == entity.MeasureType
                            && p.BuildingBlock == entity.BuildingBlock
                            && p.BuildingFloor == entity.BuildingFloor
                            && p.ProjectStandardId == entity.ProjectStandardId
                            && p.TaskType == entity.TaskType
                            && p.TaskProperty == entity.TaskProperty);

            if (entity.MeasureType == MeasureTypeEnum.机器人任务.GetString())
            {
                foreach (var item in list)
                {
                    var arr = item.RobotCategory.Split("|", StringSplitOptions.None).ToList();
                    foreach (var t in arr)
                    {
                        if (entity.RobotCategory.Contains(t) && item.TemplateCraft == entity.TemplateCraft && item.TaskId != entity.TaskId)
                            throw new OperationException("B00548".SurfaceLocalizer());
                    }
                }
            }
            else
            {
                if (list.Count > 0 && list.FirstOrDefault(p => p.TaskId != entity.TaskId) != null)
                    throw new OperationException("B00548".SurfaceLocalizer());
            }
        }

        /// <summary>
        /// 获取任务站点列表
        /// </summary>
        /// <param name="model"></param>
        /// <param name="entity"></param>
        /// <param name="pointTypes"></param>
        /// <param name="needTaskTemplates">是否需要站点测量项</param>
        /// <param name="taskTemplates"></param>
        /// <returns></returns>
        /// <exception cref="ApiResultException"></exception>
        private async ValueTask<(List<TaskPoints>, List<MSTaskPoint2ManualMeasurement>)> GetTaskPoints(TaskFm model, MsTask entity, List<MsPointType> pointTypes, bool needTaskTemplates = true, List<MsTaskMeasureItemTemplate> taskTemplates = null)
        {
            if (model.HouseMapPoints.IsEmpty())
            {
                throw new OperationException("B00557".SurfaceLocalizer());
            }
            List<TaskPoints> taskPoints = new List<TaskPoints>();
            List<MSTaskPoint2ManualMeasurement> measureItems = new List<MSTaskPoint2ManualMeasurement>();
            foreach (var item in model.HouseMapPoints)
            {
                #region 创建测量站点

                string robotJsonStr = GetUseStandardsJsonStr(model.PointTypes, 0, item.TypeId);
                var taskPoint = new TaskPoints
                {
                    TaskId = entity.TaskId,
                    pointId = Guid.NewGuid(),
                    status = PointStatus.开始测量,
                    rate = RateStatus.低,
                    x = item.x,
                    y = item.y,
                    offsetX = item.offsetX,
                    offsetY = item.offsetY,
                    pintIndex = item.pointIndex,
                    HouseTypeName = item.HouseTypeName,   // 户型图名称
                    HouseTypeKey = item.HouseTypeKey,     // 户型图Key
                    UseStandards = model.UseStandards.ToJsonStr().Replace("\"robot\":[]", $"\"robot\":[{robotJsonStr}]"),
                    MsPointTypeId = pointTypes.Where(x => x.Id == item.TypeId).FirstOrDefault().Id
                };

                taskPoints.Add(taskPoint);

                #endregion 创建测量站点

                //获取测量点对应测量项
                if (needTaskTemplates && taskTemplates.IsNotEmpty())
                    await GetHouseMapMeasureItems(measureItems, model, taskTemplates, taskPoint);
            }

            return (taskPoints, measureItems);
        }

        /// <summary>
        /// 复制任务站点列表
        /// </summary>
        private async ValueTask<(List<TaskPoints>, List<MSTaskPoint2ManualMeasurement>)> CopyTaskPoints(TaskFm model, MsTask entity, bool needTaskTemplates = true, List<MsTaskMeasureItemTemplate> taskTemplates = null)
        {
            var taskPoints = await MsTaskPointsRepository.GetTaskPoints(model.TaskId);
            if (taskPoints.IsEmpty())
            {
                throw new OperationException("B00571".SurfaceLocalizer());
            }

            List<TaskPoints> copyTaskPoints = new List<TaskPoints>();
            List<MSTaskPoint2ManualMeasurement> copyMeasureItems = new List<MSTaskPoint2ManualMeasurement>();
            DateTime dt = DateTime.Now;
            foreach (var item in taskPoints)
            {
                #region 复制站点

                string robotJsonStr = GetUseStandardsJsonStr(model.PointTypes, 0, item.MsPointTypeId);
                var copyTaskPoint = item.CopyTo<TaskPoints>();
                copyTaskPoint.pointId = Guid.NewGuid();
                copyTaskPoint.rate = RateStatus.低;        // 默认低分辨率
                copyTaskPoint.TaskId = entity.TaskId;
                copyTaskPoint.status = PointStatus.开始测量;
                copyTaskPoint.CreatedDate = dt;
                copyTaskPoint.LastUpdatedDate = dt;
                copyTaskPoint.filePath = string.Empty;
                copyTaskPoint.ErrorMessage = string.Empty;
                copyTaskPoint.UseStandards = model.UseStandards.ToJsonStr().Replace("\"robot\":[]", $"\"robot\":[{robotJsonStr}]");  // 机器测量项
                copyTaskPoint.IsManualMeasureInput = false;
                copyTaskPoint.PictureJson = string.Empty;
                copyTaskPoint.HouseTypeName = item.HouseTypeName;   // 户型图名称
                copyTaskPoint.HouseTypeKey = item.HouseTypeKey;     // 户型图Key
                copyTaskPoint.SubPointList = string.Empty;          // 清空子站点信息

                copyTaskPoints.Add(copyTaskPoint);

                #endregion 复制站点

                //获取测量点对应测量项
                if (needTaskTemplates && taskTemplates.IsNotEmpty())
                    await GetHouseMapMeasureItems(copyMeasureItems, model, taskTemplates, copyTaskPoint);
            }

            return (copyTaskPoints, copyMeasureItems);
        }

        /// <summary>
        /// 根据站点类型获取用户选择的机器测量项
        /// </summary>
        /// <param name="pointTypes">站点类型数组</param>
        /// <param name="type">站点类型</param>
        /// <returns>机器测量项JSON</returns>
        private string GetUseStandardsJsonStr(List<MsPointTypeDto> pointTypes, int type = 0, Guid? pointTypeId = null)
        {
            var pointType = pointTypes.Where(x => (type == 0 || x.Type == type) && (pointTypeId == null || x.Id == pointTypeId)).FirstOrDefault();
            if (pointType == null)
            {
                Logger.Info(pointType.ToJsonStr(), new Exception(pointTypeId.ToString()));
                throw new OperationException("B00572".SurfaceLocalizer());
            }

            string rootJsonStr = string.Empty;
            foreach (var mi in pointType.MeasureItem)
            {
                // 防止重复选中不同工艺同一测量项
                if (!mi.IsChecked || rootJsonStr.Contains(mi.Code))
                {
                    continue;
                }
                rootJsonStr += $"\"{mi.Code}\",";
            }
            if (string.IsNullOrWhiteSpace(rootJsonStr))
            {
                return string.Empty;
            }
            return rootJsonStr.Substring(0, rootJsonStr.Length - 1);    // 去掉结尾逗号
        }

        /// <summary>
        /// 获取测量点对应测量项
        /// </summary>
        private async Task GetHouseMapMeasureItems(List<MSTaskPoint2ManualMeasurement> measureItems, TaskFm model, List<MsTaskMeasureItemTemplate> taskTemplates, TaskPoints taskPoint)
        {
            var houseMapMeasureItems = await MsMeasureItemRepository.GetMeasureItemTemplate(model.HouseMapId, taskPoint.pintIndex);
            if (houseMapMeasureItems.IsNotEmpty())
            {
                foreach (var manMeaureItem in houseMapMeasureItems)
                {
                    var pointMeasuteItem = JsonConvert.DeserializeObject<UseStandard>(taskPoint.UseStandards);
                    if (!pointMeasuteItem.man.Contains(manMeaureItem.Code) && !pointMeasuteItem.robot.Contains(manMeaureItem.Code))
                    {
                        continue;
                    }
                    var mi = new MSTaskPoint2ManualMeasurement
                    {
                        MSTaskPoint2ManualMeasurementId = Guid.NewGuid(),
                        PointId = taskPoint.pointId,
                        TaskId = taskPoint.TaskId,
                        ManualMeasurementTypeId = manMeaureItem.Id,
                        Title = manMeaureItem.Title,
                        Code = manMeaureItem.Code,
                        Unit = "mm",
                        MsTaskMeasureItemTemplateId = taskTemplates.Where(x => x.TaskId == taskPoint.TaskId && x.Id == manMeaureItem.Id).FirstOrDefault().MsTaskMeasureItemTemplateId
                    };
                    mi.ValueDesign = GetDesignValueJsonStr(manMeaureItem);
                    measureItems.Add(mi);
                }
            }
        }

        /// <summary>
        /// 获取DesignValues的json字符串
        /// </summary>
        /// <param name="measure"></param>
        /// <returns></returns>
        public static string GetDesignValueJsonStr(MeasureItem measure)
        {
            string designValueStr = string.Empty;
            if (measure.DesignValues.IsEmpty())
            {
                return "{}";
            }
            foreach (var des in measure.DesignValues)
            {
                designValueStr += $"\"{des.Key}\":{(int)des.Value},";
            }
            if (!string.IsNullOrEmpty(designValueStr))
            {
                designValueStr = designValueStr.Substring(0, designValueStr.Length - 1);
            }
            return $"{{{designValueStr}}}";
        }

        /// <summary>
        /// 更新任务
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        /// <exception cref="ApiResultException"></exception>
        public async ValueTask<MsTask> UpdateTask(TaskFm model)
        {
            model.Craft = model.Craft ?? "";
            bool isExists = await MsTaskRepository.AnyAsync(p => p.TaskId == model.TaskId && p.UserId == tokenModel.Id && p.Status == MsTask.TaskStatus.未完成);
            if (!isExists)
                throw new OperationException("B00575".SurfaceLocalizer());
            // 获取户型图站点
            model.HouseMapPoints = await MsHouseMapRepository.GetPointTypes(model.ProjectId, model.HouseMapId);
            if (model.HouseMapPoints.IsEmpty())
                throw new OperationException("B00557".SurfaceLocalizer());

            return model.MeasureType switch
            {
                MeasureTypeEnum.实测实量任务 => await AddorUpdateTask(model, true),
                MeasureTypeEnum.机器人任务 => await AddOrUpdateRobotTask(model, true),
                MeasureTypeEnum.建模任务 or MeasureTypeEnum.排版任务 => await AddorUpdateModelingTask(model, true),
                _ => throw new OperationException("NotSupportedTask".SurfaceLocalizer()),
            };
        }

        /// <summary>
        /// 批量删除任务
        /// </summary>
        /// <param name="taskIds"></param>
        /// <returns></returns>
        /// <exception cref="ApiResultException"></exception>
        public async Task DeleteTasks(List<Guid> taskIds)
        {
            // 查询是否存在不是当前用户创建的任务
            bool isExists = await MsTaskRepository.AnyAsync(p => taskIds.Contains(p.TaskId) && p.UserId != tokenModel.Id);
            if (isExists)
                throw new OperationException("NoAuthorized".SurfaceLocalizer());

            List<Guid> finishIds = new List<Guid>();
            var taskList = await MsTaskRepository.WhereAsNoTrackingAsync(p => taskIds.Contains(p.TaskId));
            foreach (var id in taskIds)
            {
                var task = taskList.FirstOrDefault(p => p.TaskId == id);
                if (task == null)
                    throw new OperationException("B00581".SurfaceLocalizer());

                if (task.Status == MsTask.TaskStatus.未完成)
                {
                    //未执行，直接删除
                    MsTaskRepository.Remove(task);
                }
                else if (task.Status == MsTask.TaskStatus.已完成 || task.Status == MsTask.TaskStatus.已合并)
                {
                    //已完成状态下要检查是否已同步
                    var report = await MsTaskReportRepository.GetTaskReportForTaskId(task.TaskId);
                    if (report != null)
                    {
                        MsTaskReportRepository.Remove(report);
                    }
                    MsTaskRepository.Remove(task);
                    finishIds.Add(id);
                }
                else
                {
                    throw new OperationException("B00582".SurfaceLocalizer());
                }
            }

            await UnitOfWork.SaveChangesAsync();
        }

        /// <summary>
        /// 获取任务详情
        /// </summary>
        /// <param name="taskId"></param>
        /// <returns></returns>
        public async ValueTask<TaskSfm> GetTaskDetail(Guid taskId)
        {
            var taskInfo = await MsTaskRepository.FirstOrDefaultAsync(p => p.TaskId == taskId && !p.IsDeleted);
            if (taskInfo == null)
                throw new OperationException("TaskNotExists".SurfaceLocalizer());
            if (taskInfo.UserId != tokenModel.Id)
                throw new OperationException("NoAuthorized".SurfaceLocalizer());

            var result = await MsTaskRepository.GetModel(taskInfo);
            if (result == null)
                throw new OperationException("TaskNotExists".SurfaceLocalizer());

            result.PointTypes = await MsPointTypeRepository.GetTaskStandards(result.ProjectStandardId, taskId, result.ProjectId);

            return result;
        }

        /// <summary>
        /// 绑定任务的订阅消息模板
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="templateId"></param>
        /// <param name="openId"></param>
        /// <returns></returns>
        public async ValueTask<ApiResult> BindTaskMessageTemplate(Guid[] ids, string templateId, string openId)
        {
            var templates = cfg.GetSection("WxTemplateIds").Get<string[]>();
            if (templates.IsEmpty() || !templates.Contains(templateId))
                return new ApiResult { Code = AjaxCode.Fail, Message = "ErrorTemlpate".SurfaceLocalizer() };
            if (string.IsNullOrEmpty(openId))
                return new ApiResult { Code = AjaxCode.Fail, Message = "OpenIdIsEmpty".SurfaceLocalizer() };
            var taskList = await MsTaskRepository.WhereAsNoTrackingAsync(p => ids.Contains(p.TaskId) && p.UserId == tokenModel.Id && !p.IsDeleted);
            if (taskList.IsEmpty())
                return new ApiResult { Code = AjaxCode.Fail, Message = "TaskNotExists".SurfaceLocalizer() };

            List<MsTaskWxMessage> list = new List<MsTaskWxMessage>();
            foreach (var item in taskList)
            {
                var messageInfo = new MsTaskWxMessage
                {
                    Id = Guid.NewGuid(),
                    TaskId = item.TaskId,
                    TemplateId = templateId,
                    OpenId = openId,
                    IsDeleted = false,
                    Status = 0,
                    CreatedBy = tokenModel.Id,
                    CreatedDate = DateTime.Now,
                    LastUpdatedBy = tokenModel.Id,
                    LastUpdatedDate = DateTime.Now
                };
                list.Add(messageInfo);
            }

            var isSuccess = await MsTaskWxMessageRepository.AddMessageAsync(list);
            if (isSuccess)
                return new ApiResult { Code = AjaxCode.Success };
            else
                return new ApiResult { Code = AjaxCode.Fail, Message = "SubscribeTemplateFailed".SurfaceLocalizer() };
        }

        /// <summary>
        /// 批量更新任务状态
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async ValueTask<ApiResult> UpdateTaskStatusAsync(UpdateTaskStatusRequestDto dto)
        {
            var list = await MsTaskRepository.WhereAsNoTrackingAsync(p => dto.TaskIds.Contains(p.TaskId) && p.UserId == tokenModel.Id && !p.IsDeleted);

            if (list.Select(p => p.TaskId).Distinct().Count() != dto.TaskIds.Distinct().Count())
                return new ApiResult { Code = AjaxCode.Unauthorized, Message = "NoAuthorized".SurfaceLocalizer() };

            var isSuccess = await MsTaskRepository.UpdateTaskStatusAsync(dto);

            return isSuccess ? new ApiResult { Code = AjaxCode.Success } : new ApiResult { Code = AjaxCode.Fail };
        }

        /// <summary>
        /// 小程序下发任务
        /// </summary>
        public async ValueTask<bool> IssueTask(Guid taskId)
        {
            //todo:可以返回taskSfm，这样前端就不用再次请求api/miniapp/ms/Task/Detail
            try
            {
                var existsSql = $"SELECT EXISTS(select 1 from tasktable t WHERE t.uuid = '{taskId}')";
                var exist = (bool)await PgSqlHelper.ExecuteScalarAsync(System.Data.CommandType.Text, existsSql);
                if (exist) return true;
                var taskSfm = await GetTaskDetail(taskId);
                if (taskSfm == null) return false;
                var housenamelist = "[]";
                if (!string.IsNullOrWhiteSpace(taskSfm.HouseType))
                {
                    var houseTypes = JsonConvert.DeserializeObject<List<KeyAndName>>(taskSfm.HouseType);
                    if (houseTypes?.Count > 0)
                        housenamelist = houseTypes.Select(x => x.Name).ToJsonStr();
                }

                var secondaryStructureType = taskSfm.ProjectStage == "砌筑工程" && taskSfm.SecondaryStructureType == 0 ? 1 : (int)taskSfm.SecondaryStructureType;

                var insertSql = @"INSERT INTO tasktable (uuid, ""name"", taskstandard, taskstage, createtime, tasktype, craft, supportstandard,  sessionid, taskexecutiontype, robotmeasureitems, measuretype,  secondarystructuretype, enabledeeplearning, rulermode,""ProjectGuid"",""CompanyGuid"",""tasktableGuid"",housenamelist) VALUES(@uuid, @name, @taskstandard, @taskstage, @createtime, @tasktype,  @craft, @supportstandard, @sessionid, @taskexecutiontype, null, @measuretype,  @secondarystructuretype, 0, @rulermode,@projectid,@companyid,@tasktableguid,@housenamelist);";

                var parameters = new NpgsqlParameter[]
                {
                new NpgsqlParameter("uuid",taskId),
                new NpgsqlParameter("name",taskSfm.TaskName),
                new NpgsqlParameter("taskstandard",NpgsqlDbType.Jsonb){Value=$"[{taskSfm.UsestandardAllInfo}]"},
                new NpgsqlParameter("taskstage",taskSfm.ProjectStage),
                new NpgsqlParameter("createtime",DateTime.Now.ToDateTimeStandardString()),
                new NpgsqlParameter("tasktype",$"{(int)taskSfm.TaskType}"),
                new NpgsqlParameter("craft",taskSfm.Craft),
                new NpgsqlParameter("housenamelist",housenamelist){NpgsqlDbType=NpgsqlDbType.Jsonb},
                new NpgsqlParameter("supportstandard",taskSfm.SupportStandard),
                new NpgsqlParameter("sessionid",Guid.NewGuid().ToString("N")),
                new NpgsqlParameter("taskexecutiontype","2"),
                new NpgsqlParameter("measuretype","1"),
                new NpgsqlParameter("secondarystructuretype",secondaryStructureType.ToString()),
                new NpgsqlParameter("rulermode",(int)taskSfm.RulerMode),
                new NpgsqlParameter("projectid",taskSfm.ProjectId),
                new NpgsqlParameter("companyid",tokenModel.CompanyGuid),
                new NpgsqlParameter("tasktableguid",Guid.NewGuid())
                };
                var insert_row = await Db.Database.ExecuteSqlRawAsync(insertSql, parameters);
                await UnitOfWork.SaveChangesAsync();
                return insert_row == 1;
            }
            catch (Exception ex)
            {
                Logger.Error(string.Format("下发任务出错，错误信息为{0}", ex.Message), ex);
                return false;
            }
        }

        /// <summary>
        /// 站点采集
        /// </summary>
        public async ValueTask<bool> CollectTaskPoint(CollectTaskPointDto dto)
        {
            try
            {
                var taskEntity = await MsTaskRepository.GetByIdAsync(dto.TaskId);
                if (taskEntity == null) return false;
                var algorthmconfig = await AlgoTemplateService.GetAlgorthmconfig(dto.TaskId);
                var now = DateTime.Now.ToDateTimeStandardString();

                #region 人工、机器测量项

                var taskPoint = await MsTaskPointsRepository.GetAll().Where(x => x.TaskId == dto.TaskId && x.pintIndex == dto.Index).Select(x => new { x.pointId, x.UseStandards }).FirstOrDefaultAsync();
                var pointMeasureItems = await MSTaskPoint2ManualMeasurementRepository.GetPointMeasureItems(dto.TaskId, taskPoint.pointId);
                string robotJsonStr = string.Empty;
                //人工测量项目
                string manJsonStr = string.Empty;
                foreach (var item in pointMeasureItems)
                {
                    // 注：华润版本将"外窗洞口尺寸"和"门洞尺寸"作为机器测量项
                    if (item.Type == 1 || item.Code == "r-waichuangdongkouchicun" || item.Code == "r-mendongchicun" || item.Code == "r-menchuangdongkouchicun")
                    {
                        robotJsonStr += $"{{\"Code\":\"{item.Code}\",\"Unit\":\"{item.Unit}\",\"ManualMeasurementTypeId\":\"{item.ManualMeasurementTypeId}\",\"Values\":[], \"DesignValue\":{item.DesignValues}}},";
                    }
                    else if (item.Type == 0)
                    {
                        if (!string.IsNullOrWhiteSpace(item.Values) && !string.Equals("[]", item.Values))
                        {
                            var actualValue = item.Values.ToObject<List<MeasuredValue>>();
                            var keys = actualValue.Select(x => x.Key).Distinct().ToList();  // 实际测量项值数量（如：长，宽和高就是3）
                            int flag = 1;
                            item.Values = string.Empty;
                            string actualValueJson = string.Empty;
                            foreach (var a in actualValue)
                            {
                                if (string.Equals(item.Code, "r-hunningtuqiangdu", StringComparison.OrdinalIgnoreCase))
                                {
                                    a.Key = "Strength";
                                }
                                actualValueJson += $"\"{a.Key}\":{a.Value},";
                                if (keys.Count == flag)
                                {
                                    actualValueJson = $"{{{actualValueJson.Substring(0, actualValueJson.Length - 1)}}},";
                                    item.Values += actualValueJson;
                                    actualValueJson = string.Empty;
                                    flag = 0;
                                }
                                flag++;
                            }
                            item.Values = item.Values.Substring(0, item.Values.Length - 1);
                            manJsonStr += $"{{\"Code\":\"{item.Code}\",\"Unit\":\"{item.Unit}\",\"ManualMeasurementTypeId\":\"{item.ManualMeasurementTypeId}\",\"Values\":[{item.Values}], \"DesignValue\":{item.DesignValues}}},";
                        }
                    }
                }

                if (!string.IsNullOrEmpty(robotJsonStr))
                {
                    robotJsonStr = robotJsonStr.Substring(0, robotJsonStr.Length - 1);
                    Logger.Info(robotJsonStr);
                }
                robotJsonStr = $"[{robotJsonStr}]";
                if (!string.IsNullOrEmpty(manJsonStr))
                {
                    manJsonStr = manJsonStr.Substring(0, manJsonStr.Length - 1);
                    Logger.Info($"站点:{dto.Index},人工测量项:{manJsonStr}");
                }
                manJsonStr = $"[{manJsonStr}]";

                #endregion 人工、机器测量项

                var pontTypeName = await MsTaskPointsRepository.GetPointTypeByTaskId(dto.TaskId, dto.Index);
                var houseTypeName = await MsTaskPointsRepository.GetAll().Where(x => x.TaskId == dto.TaskId && x.pintIndex == dto.Index).Select(x => x.HouseTypeName).FirstOrDefaultAsync() ?? string.Empty;

                var insert_taskpointtable_Sql = @"DELETE FROM taskpointtable t WHERE t.uuid  = @uuid AND t.""index"" = @index;INSERT INTO taskpointtable (uuid, ""index"", createtime, updatetime, isqualified, measurerate,  manmeasuredata, robotmeasuredesign, measureitems, ""type"", housename,  farosn, build, floor, algorthmconfig, grind, area, filepath,""taskPointTableId"") VALUES(@uuid, @index, @createtime, @updatetime, @isqualified, @measurerate, @manmeasuredata, @robotmeasuredesign, @measureitems, @type, @housename,  @farosn, @build, @floor, @algorthmconfig, @grind, @area, @filepath,@taskpointtableid);";
                var taskpointtable_parameters = new NpgsqlParameter[]
                {
                new NpgsqlParameter("uuid",dto.TaskId),
                new NpgsqlParameter("index",dto.Index),
                new NpgsqlParameter("createtime",now),
                new NpgsqlParameter("updatetime",now),
                new NpgsqlParameter("isqualified",true),
                new NpgsqlParameter("measurerate",dto.IsHighRate ? "1/5" : "1/16"),
                new NpgsqlParameter("manmeasuredata",manJsonStr){NpgsqlDbType=NpgsqlDbType.Jsonb},
                new NpgsqlParameter("robotmeasuredesign",robotJsonStr){NpgsqlDbType=NpgsqlDbType.Jsonb},
                new NpgsqlParameter("type",pontTypeName),
                new NpgsqlParameter("measureitems",taskPoint.UseStandards){NpgsqlDbType=NpgsqlDbType.Jsonb},
                new NpgsqlParameter("housename",houseTypeName),
                new NpgsqlParameter("farosn",dto.FaroSN),
                new NpgsqlParameter("build",taskEntity.BuildingBlock),
                new NpgsqlParameter("floor",taskEntity.BuildingFloor),
                new NpgsqlParameter("algorthmconfig",algorthmconfig){NpgsqlDbType=NpgsqlDbType.Jsonb},
                new NpgsqlParameter("grind","2"),
                new NpgsqlParameter("area","1"),
                new NpgsqlParameter("filepath",dto.TempFilePath),
                new NpgsqlParameter("taskpointtableid",Guid.NewGuid()),
                };

                var taskpointtable_row = await Db.Database.ExecuteSqlRawAsync(insert_taskpointtable_Sql, taskpointtable_parameters);

                var point_entity = await MsTaskPointsRepository.FirstOrDefaultAsync(x => x.TaskId == dto.TaskId && x.pintIndex == dto.Index && !x.IsDeleted);
                if (point_entity != null && point_entity.status != PointStatus.采集完成)
                {
                    point_entity.status = PointStatus.采集完成;
                    MsTaskPointsRepository.Update(point_entity, true);
                }

                var collect_entity = await MsDotCloudCollectRepository.FirstOrDefaultAsync(x => x.TaskId == dto.TaskId && x.PointIndex == dto.Index);
                if (collect_entity != null)
                {
                    collect_entity.FilePath = dto.TempFilePath;
                    MsDotCloudCollectRepository.Update(collect_entity, t => t.FilePath);
                }

                var upload_entity = await MsDotCloudUploadRepository.FirstOrDefaultAsync(x => x.TaskId == dto.TaskId && x.PointIndex == dto.Index && !x.IsDeleted);
                if (upload_entity != null && upload_entity.Success)
                {
                    upload_entity.Success = false;
                    upload_entity.Status = UploadStatusEnum.待上传;
                    MsDotCloudUploadRepository.Update(upload_entity, t => new { t.Success, t.Status });
                }

                await UnitOfWork.SaveChangesAsync();
                return taskpointtable_row >= 1;
            }
            catch (Exception ex)
            {
                Logger.Error(string.Format("站点采集出错，错误为：{0}", ex.Message), ex);
                return false;
            }
        }

        /// <summary>
        /// 保存采集作业编号
        /// </summary>
        public async ValueTask<bool> SaveCollectJobId(CollectJobDto dto)
        {
            try
            {
                var point = await MsTaskPointsRepository.FirstOrDefaultAsync(p => p.TaskId == dto.TaskId && p.pintIndex == dto.PointIndex && !p.IsDeleted);
                if (point == null)
                    throw new OperationException("TaskPointNoExists".SLocalize());
                var collect_entity = await MsDotCloudCollectRepository.FirstOrDefaultAsync(x => x.TaskId == dto.TaskId && x.PointIndex == dto.PointIndex);
                if (collect_entity == null) MsDotCloudCollectRepository.Add(new MsDotCloudCollect
                {
                    PointIndex = dto.PointIndex,
                    TaskId = dto.TaskId,
                    JodId = dto.JodId,
                    CollectTime = DateTime.Now,
                });
                else
                {
                    collect_entity.JodId = dto.JodId;
                    collect_entity.CollectTime = DateTime.Now;
                    MsDotCloudCollectRepository.Update(collect_entity, t => new { t.JodId, t.FilePath, t.CollectTime });
                }

                var point_entity = await MsTaskPointsRepository.FirstOrDefaultAsync(x => x.TaskId == dto.TaskId && x.pintIndex == dto.PointIndex && !x.IsDeleted);
                if (point_entity != null)
                {
                    point_entity.status = PointStatus.采集中;
                    MsTaskPointsRepository.Update(point_entity, true);
                }

                await UnitOfWork.SaveChangesAsync();
                return true;
            }
            catch (Exception ex)
            {
                Logger.Error(string.Format("保存采集作业编号出错，{0}", ex.Message), ex);
                return false;
            }
        }

        /// <summary>
        /// 获取采集作业编号上传状态
        /// </summary>
        public async Task<List<CollectAndUpload>> GetCollectJobId(TaskPointIndexDto dto)
        {
            var query = MsDotCloudCollectRepository.QueryUploadPoint(dto.TaskId);

            var list = (await query.AsNoTracking().ToListAsync()).Where(x => !dto.PointIndex.HasValue || x.PointIndex == dto.PointIndex).ToList();
            list.ForEach(x =>
            {
                if (x.UploadStatus == UploadStatusEnum.上传成功)
                {
                    //上传成功的站点清除jobId和临时文件路径
                    x.JodId = null;
                    x.FilePath = null;
                }
            });
            return list;
        }

        /// <summary>
        /// 获取需要上传点云的站点
        /// </summary>
        public async Task<List<CollectAndUpload>> GetNeedUploadPoint(Guid taskId)
        {
            var query = MsDotCloudCollectRepository.QueryUploadPoint(taskId).Where(x => x.UploadStatus != UploadStatusEnum.上传成功);
            return (await query.ToListAsync()).FindAll(x => !string.IsNullOrEmpty(x.FilePath));
        }

        /// <summary>
        /// 新增任务的点云上传批次
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async ValueTask<ApiResult> AddTaskUploadBatchAsync(TaskDotCloudBatchRequestDto dto)
        {
            var result = await MsTaskDotCloudBatchRepository.AddDotCloudBatchAsync(dto);

            return new ApiResult { Code = result ? AjaxCode.Success : AjaxCode.Fail };
        }

        /// <summary>
        /// 重置站点状态为开始采集
        /// </summary>
        public async ValueTask<bool> ResetPointStatus(ResetTaskPointDto dto)
        {
            var point_entity = await MsTaskPointsRepository.FirstOrDefaultAsync(x => x.TaskId == dto.TaskId && x.pintIndex == dto.PointIndex && !x.IsDeleted);
            if (point_entity == null)
                throw new OperationException("TaskPointNoExists".SLocalize());

            point_entity.status = PointStatus.开始测量;
            point_entity.ErrorMessage = dto.ErrorMsg;
            MsTaskPointsRepository.Update(point_entity, t => new { t.status, t.ErrorMessage });

            await UnitOfWork.SaveChangesAsync();
            return true;
        }

        /// <summary>
        /// 设置站点采集分辨率
        /// </summary>
        public async ValueTask<bool> SetTaskPointResolution(TaskPointResolutionDto dto)
        {
            var point = await MsTaskPointsRepository.FirstOrDefaultAsync(
                x => x.TaskId == dto.TaskId 
                && x.pintIndex == dto.PointIndex 
                && !x.IsDeleted);
            if (point == null)
            {
                throw new OperationException("TaskPointNoExists".SLocalize());
            }

            point.rate = dto.Rate;
            point.LastUpdatedDate = DateTime.Now;
            point.LastUpdatedBy = tokenModel.YunUserGuid;
            MsTaskPointsRepository.Update(point, t => new { t.status, t.LastUpdatedBy, t.LastUpdatedDate });
            await UnitOfWork.SaveChangesAsync();
            return true;
        }
    }
}